<template>
  <div class="m-authcode">
    <div v-for="(code,i) of auth" :key="i" class="m-code">
      <input
        v-model="auth[i]"
        :ref="setInputRef"
        :type="inputType"
        :disabled="loading"
        @focus="onFocus"
        @input="onInput($event, i)"
        @keydown.delete="onKeydown($event, i)" />
    </div>
  </div>
</template>
<script>
import { defineComponent, ref, toRefs, watch, onMounted, onBeforeUpdate } from 'vue'

const createArr = len => {
  return Array.from(Array(len)).map(() => '')
}
export default defineComponent({
  name: 'MAuthcode',
  emits: ['update:value'],
  props: {
    value: {
      type: Array,
    },
    length: {
      type: Number,
      default: 6
    },
    mask: {
      type: Boolean
    },
    gutter: {
      type: String
    },
    focused: {
      type: Boolean
    },
    loading: {
      type: Boolean
    }
  },
  setup (props, { emit }) {
    let auth
    const { value, length, mask, gutter, focused } = toRefs(props)

    let inputRefs = []
    const inputType = mask.value ? 'password' : 'number'

    // 值自动补长
    if (length.value !== value.value.length) {
      auth = ref(createArr(length.value)) // ['', '', '', '']
    } else {
      auth = value.value
    }

    const onKeydown = (e, i) => {
      const target = e.target.value
      // 再次删除
      if (target === '') {
        // 删除上一个，，并focus
        if (i > 0) {
          auth.value[i - 1] = ''
          inputRefs[i - 1].focus()
        }
      }
    }

    const onInput = (e, i) => {
      const target = e.target.value
      const value = Number(target)
      if (!(value >= 0) || !target) {
        // 输入非法
        return
      } else if (i === length.value - 1 && e.data) {
        // 最后一位
        auth.value[i] = +e.data
      } else if (target.length > 1) {
        // 点短信验证码
        for (let index = i; index < Math.min(target.length, length.value); index++) {
          auth.value[index] = +target[index]
        }
      }
      i < (length.value -1) && onFocus()
    }

    // 重置光标位置
    const onFocus = () => {
      let index = auth.value.findIndex(ret => ret === '')
      index = (index + length.value) % length.value
      inputRefs[index].focus()
    }

    // dom获取
    const setInputRef = (el) => {
      inputRefs.push(el)
    }
    onBeforeUpdate(() => {
      inputRefs = []
    })
    onMounted(() => {
      focused.value && onFocus()
    })
    // 数据双向绑定
    watch(auth, (nVal) => {
      emit('update:value', auth.value)
    }, { deep: true })

    return {
      auth,
      inputRefs,
      gutter,
      focused,
      inputType,
      onFocus,
      onInput,
      onKeydown,
      setInputRef
    }
  }
})
</script>
<style lang="less" scoped>
* {
  margin: 0;
  padding: 0;
  box-sizing: border-box;
}
.m-authcode {
  display: flex;

  .m-code {
    flex: 1;
    margin-left: v-bind(gutter);
    &:first-child {
      margin-left: 0;
    }
    input {
      width: 100%;
      height: 50px;
      border: none;
      text-align: center;
      font-size: 20px;
      color: #333;
    }
  }
}

</style>
